package uk.co.hs.dao.web.admin;

import java.util.ArrayList;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.Hibernate;
import org.hibernate.Query;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.springframework.stereotype.Repository;

import uk.co.hs.dao.generic.UtilisoftGenericDao;
import uk.co.hs.domain.web.WebUser;

@Repository("hs_webUserDao")
public class WebUserDao extends UtilisoftGenericDao<WebUser, Long>
{
  @SuppressWarnings("unchecked")
  public List<WebUser> getAllWebUsers()
  {
    return getSession().createQuery("FROM WebUser user WHERE user.endDate IS NULL ORDER BY user.active DESC, user.username").list();
  }

  /**
   * Get Web User by Username.
   * @param aUsername The Username.
   * @return The Web User.
   */
  public WebUser getWebUser(final String aUsername)
  {
    Query query = getSession().createQuery("FROM WebUser user WHERE user.endDate IS NULL and user.username = :username");
    query.setParameter("username", aUsername);
    return (WebUser) query.uniqueResult();
  }

  @SuppressWarnings("unchecked")
  public WebUser getWebUserIncludingPasswordHistory(final String aUserName)
  {
    Criteria criteria = getSession().createCriteria(WebUser.class);
    criteria.add(Restrictions.eq("username", aUserName));
    criteria.add(Restrictions.isNull("endDate"));
    criteria.addOrder(Order.asc("username"));
    List<WebUser> results = criteria.list();
    if (results.isEmpty())
    {
      return null;
    }
    WebUser user = results.get(0);
    Hibernate.initialize(user.getPasswordHistory());
    return user;
  }

  @SuppressWarnings("unchecked")
  public List<WebUser> getWebUsers(Boolean isActiveUsers,
                                   Boolean isDeActiveUsers)
  {
    if (!isActiveUsers.booleanValue() && !isDeActiveUsers.booleanValue())
    {
      return new ArrayList<WebUser>();
    }

    StringBuffer query = new StringBuffer();
    query.append("FROM WebUser user ");
    if (isActiveUsers.booleanValue() && !isDeActiveUsers.booleanValue())
    {
      query.append("WHERE user.active = 1 AND user.endDate IS NULL");
    }
    else if (!isActiveUsers.booleanValue() && isDeActiveUsers.booleanValue())
    {
      query.append("WHERE user.active = 0 AND user.endDate IS NULL");
    }
    else
    {
      query.append("WHERE user.endDate IS NULL");
    }

    return getSession().createQuery(query.toString()).list();
  }

  @SuppressWarnings("unchecked")
  public List<WebUser> getWebUsers(Boolean isActiveUsers,
                                   Boolean isDeActiveUsers,
                                   Integer aFirstRec,
                                   Integer aMaxRec,
                                   String aSortField,
                                   String aSortOrder)
  {
    if (!isActiveUsers.booleanValue() && !isDeActiveUsers.booleanValue())
    {
      return new ArrayList<WebUser>();
    }

    StringBuffer queryString = new StringBuffer();
    queryString.append("FROM WebUser user ");
    if (isActiveUsers.booleanValue() && !isDeActiveUsers.booleanValue())
    {
      queryString.append("WHERE user.active = 1 AND user.endDate IS NULL ");
    }
    else if (!isActiveUsers.booleanValue() && isDeActiveUsers.booleanValue())
    {
      queryString.append("WHERE user.active = 0 AND user.endDate IS NULL ");
    }
    else
    {
      queryString.append("WHERE user.endDate IS NULL ");
    }

    if (aSortField != null && aSortOrder != null)
    {
      queryString.append("ORDER BY user." + aSortField + " " + aSortOrder);
    }

    return getSession().createQuery(queryString.toString()).setFirstResult(aFirstRec.intValue()).setMaxResults(aMaxRec.intValue()).list();
  }

  public Integer getWebUserCount(Boolean isActiveUsers, Boolean isDeActiveUsers)
  {
    if (!isActiveUsers.booleanValue() && !isDeActiveUsers.booleanValue())
    {
      return new Integer(0);
    }

    StringBuffer query = new StringBuffer();
    query.append("SELECT COUNT(*) FROM WebUser user ");
    if (isActiveUsers.booleanValue() && !isDeActiveUsers.booleanValue())
    {
      query.append("WHERE user.active = 1 AND user.endDate IS NULL");
    }
    else if (!isActiveUsers.booleanValue() && isDeActiveUsers.booleanValue())
    {
      query.append("WHERE user.active = 0 AND user.endDate IS NULL");
    }
    else
    {
      query.append("WHERE user.endDate IS NULL");
    }

    return (Integer) getSession().createQuery(query.toString()).list().get(0);
  }

  @SuppressWarnings("unchecked")
  public boolean webUserExists(String aUsername, boolean aIncludeDeleted)
  {
    StringBuffer queryString = new StringBuffer("SELECT COUNT(distinct username) FROM WebUser WHERE lower(username) = ?");
    if (!aIncludeDeleted)
    {
      queryString.append(" AND endDate IS NULL");
    }

    Query query = getSession().createQuery(queryString.toString());
    query.setParameter("username", aUsername);
    List<Long> results = query.list();
    Long count = results.get(0);
    return count.intValue() > 0;
  }

  public void incrementFailedLoginAttempts(WebUser aUser)
  {
    aUser.setConsecutiveFailedLogins(aUser.getConsecutiveFailedLogins() + 1);
    makePersistent(aUser);
  }

  public void resetFailedLoginAttempts(WebUser aUser)
  {
    aUser.setConsecutiveFailedLogins(0);
    makePersistent(aUser);
  }

  public void lockUser(WebUser aUser)
  {
    aUser.setLocked(true);
    makePersistent(aUser);
  }
}
